/**
  ******************************************************************
  * @file    main.c
  * @author  Merlin	
  * @version V1.0
  * @date    2022-5-31
  * @brief   控制WS2812B实现塞尔达文字石板	
  ******************************************************************
  * @attention
  * verimake 用于ch549的进阶控制学习
  *
  ******************************************************************
  */
#include <CH549_sdcc.H>	   //ch549的头文件，其中定义了单片机的一些特殊功能寄存器
#include <CH549_DEBUG.h>   //CH549官方提供库的头文件，定义了一些关于主频，延时，串口设置，看门口，赋值设置等基础函数
#include <stdlib.h>          //调用随机数函数
#define COLUMN_LED 13                  //灯的列数
#define COW_LED 21                     //灯的行数
#define PIXEL 4                        //像素长度
#define COW  (COW_LED+PIXEL*4-2)       //行数据长度

unsigned char buf_R[COLUMN_LED][COW] = {{0}};//假定灯带长度数据条的输出颜色缓存
unsigned char buf_G[COLUMN_LED][COW] = {{0}};
unsigned char buf_B[COLUMN_LED][COW] = {{0}};

unsigned char Column[COLUMN_LED];            //列定位灯带标志
 
unsigned char RGB_R[COLUMN_LED];//输入颜色缓存
unsigned char RGB_G[COLUMN_LED];
unsigned char RGB_B[COLUMN_LED];

/***********************************************************************
名    称    ：WS2812B时序部分
功    能    ：定义WS2812B的1码0码及复位码，以及根据RGB值为WS2812B赋予数据
************************************************************************/

#define WS2812 P2_2                           //设定p2.2口作为灯带的输入口
#define _nop() __asm NOP __endasm             //将nop指令定义为宏

//1码，高电平850ns 低电平400ns 误差正负150ns
#define RGB_1() do{WS2812 = 1;\
    _nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
    _nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
    _nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
    _nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
	WS2812 = 0;}while(0) 
  //此处加do while循环可以将宏定义的部分可以被识别为语句，方便纠错，下同

//0码，高电平400ns 低电平850ns 误差正负150ns
#define RGB_0() do{WS2812 = 1;\
		_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
        _nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
		WS2812 = 0;\
		_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();_nop();\
		}while(0)

//发送24位数据
void Send_2811_24bits(unsigned char G8,unsigned char R8,unsigned char B8)
{
	  
	  char n = 0;
	  //发送G8位
		for(n=0;n<8;n++)
		{
			
			if(G8&0x80)
			{
				RGB_1();
			}
			else  
			{
			  RGB_0();
			}
            G8<<=1;
		}
		//发送R8位
		for(n=0;n<8;n++)
		{
			
			if(R8&0x80)
			{
				RGB_1();
			}
			else  
			{
				RGB_0();
			}
			R8<<=1;
		}
		//发送B8位
	  for(n=0;n<8;n++)
		{
		
			if(B8&0x80)
			{
				RGB_1();
			}
			else  
			{
			  RGB_0();
			}
      	B8<<=1;
		}
}

//复位码
void RGB_Rst()
{
		WS2812 = 0;
		mDelayuS( 50 );
}

//缓存清0
void Buf_Put0()
{
	unsigned char i,j;
	for (j = 0; j < COLUMN_LED; j++)
		{
		  for(i=0;i<COW;i++)
	      {
			buf_R[j][i] = 0; 
			buf_G[j][i] = 0;
			buf_B[j][i] = 0;
		  }
		}
}

//颜色缓存
void genColor()
    {
		unsigned int j;
        float h , s = 1.0 , v = 1.0;                          //色相等分，明度和饱和度均设定为满
		for (j = 0; j < COLUMN_LED; j++)
		{		
		h = j*1.0/COLUMN_LED;
		h *= 360.0f;                                          //HSV转RGB
        if (s == 0)
            {RGB_R[j] = RGB_G[j] = RGB_B[j] = v;}
        else
        {
            h = h / 60.0;
            int i = (int)h;
            float C = h - i;
            v *=255.0;
            float X = v * (1 - s) * 255.0;
            float Y = v * (1 - s * C) * 255.0;
            float Z = v * (1 - s * (1 - C)) * 255.0;
            switch (i)
            {
                case 0: RGB_R[j]  = v; RGB_G[j]  = Z; RGB_B[j]  = X; break;
                case 1: RGB_R[j]  = Y; RGB_G[j]  = v; RGB_B[j]  = X; break;
                case 2: RGB_R[j]  = X; RGB_G[j]  = v; RGB_B[j]  = Z; break;
                case 3: RGB_R[j]  = X; RGB_G[j]  = Y; RGB_B[j]  = v; break;
                case 4: RGB_R[j]  = Z; RGB_G[j]  = X; RGB_B[j]  = v; break;
                case 5: RGB_R[j]  = v; RGB_G[j]  = X; RGB_B[j]  = Y; break;
            }
        }
		}
    }

//设定像素段
void Set_Color(unsigned char column,unsigned char cow)
{
	  unsigned char i;
	  for(i=0;i<PIXEL;i++)
	  {  
		buf_R[column][cow+PIXEL-i] = RGB_R[column] / (PIXEL * i + 1);
		buf_G[column][cow+PIXEL-i] = RGB_G[column] / (PIXEL * i + 1);
		buf_B[column][cow+PIXEL-i] = RGB_B[column] / (PIXEL * i + 1);
	  }
	  for(i=1;i<PIXEL;i++)
	  {  
		buf_R[column][cow+PIXEL+i] = RGB_R[column] / (PIXEL * i + 1);
		buf_G[column][cow+PIXEL+i] = RGB_G[column] / (PIXEL * i + 1);
		buf_B[column][cow+PIXEL+i] = RGB_B[column] / (PIXEL * i + 1);
	  }
}

//将显示区的数据发送显示
void Send_ALL()
{
	unsigned char i,j;
	for (j = 0; j < COLUMN_LED; j++)                          
		{
		for(i=PIXEL*2-1;i<COW-PIXEL*2+1;i++)
		{
		Send_2811_24bits(buf_G[j][i],buf_R[j][i],buf_B[j][i]);
		}
		}
		mDelaymS(50);
}

/********************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*********************************************************************/
void main(void)
{
  unsigned int m,i,j;
  CfgFsys();                        //CH549时钟选择配置
  mDelaymS(20);
  genColor();                       //颜色预设
  for ( j = 0; j < COLUMN_LED; j++)     //所有列的流水灯进入就绪状态
  {
	  Column[j] = COW_LED+PIXEL*2-1;
  }
  
  /* 主循环 */
  while (1)
{
   Buf_Put0();                    //数据条清0
   m = rand() % COLUMN_LED;       //取随机数
   if (Column[m] == COW_LED+PIXEL*2-1) {Column[m] = 0;}       //选中的列若以就绪开启流水灯
   for ( i = 0; i < COLUMN_LED; i++)                          //检测每一列的状态
   {
	   if (Column[i] < COW_LED+PIXEL*2-1)                     //若列数据未走完给该列赋值
	   {
		   if (i % 2)                                         //判断单双列
		   {
			   Set_Color(i,COW_LED+PIXEL*2-1-Column[i]);      //双列
		   }
		   else
		   {
			   Set_Color(i,Column[i]);                        //单列
		   }
		  Column[i]++;                                        //下次循环走下一个瞬间的数据
	   }
	   
   }
   
   Send_ALL();                                                //将该时间数据发送显示
}
}